﻿using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;

namespace Purdue.Helper
{
    public static class SevenZipHelper
    {
        private static bool dllFound;
        private static Assembly assembly;

        [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "1#", Justification = "Conformance to existing API due to lazy assembly loading.")]
        public static bool CheckArchive(string archive, out bool result)
        {
            result = false;

            if (Check())
            {
                var type = assembly.GetType("SevenZip.SevenZipExtractor");
                var extractor = Activator.CreateInstance(type, new object[] { archive });
                result = (bool)type.GetMethod("Check").Invoke(extractor, null);
                return true;
            }

            return false;
        }

        [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "2#", Justification = "Conformance to existing API due to lazy assembly loading.")]
        public static bool CheckArchive(string archive, string password, out bool result)
        {
            result = false;

            if (Check())
            {
                var type = assembly.GetType("SevenZip.SevenZipExtractor");
                var extractor = Activator.CreateInstance(type, new object[] { archive, password });
                result = (bool)type.GetMethod("Check").Invoke(extractor, null);
                return true;
            }

            return false;
        }

        public static bool ExtractArchive(string archive, string directory)
        {
            if (Check())
            {
                var type = assembly.GetType("SevenZip.SevenZipExtractor");
                var extractor = Activator.CreateInstance(type, new object[] { archive });
                type.GetMethod("ExtractArchive").Invoke(extractor, new object[] { directory });
                return true;
            }

            return false;
        }

        public static bool ExtractArchive(string archive, string directory, string password)
        {
            if (Check())
            {
                var type = assembly.GetType("SevenZip.SevenZipExtractor");
                var extractor = Activator.CreateInstance(type, new object[] { archive, password });
                type.GetMethod("ExtractArchive").Invoke(extractor, new object[] { directory });
                return true;
            }

            return false;
        }

        [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "1#", Justification = "Conformance to existing API due to lazy assembly loading.")]
        public static bool CheckStream(Stream stream, out bool result)
        {
            result = false;

            if (Check())
            {
                var type = assembly.GetType("SevenZip.SevenZipExtractor");
                var extractor = Activator.CreateInstance(type, new object[] { stream });
                result = (bool)type.GetMethod("Check").Invoke(extractor, null);
                return true;
            }

            return false;
        }

        [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "2#", Justification = "Conformance to existing API due to lazy assembly loading.")]
        public static bool CheckStream(Stream stream, string password, out bool result)
        {
            result = false;

            if (Check())
            {
                var type = assembly.GetType("SevenZip.SevenZipExtractor");
                var extractor = Activator.CreateInstance(type, new object[] { stream, password });
                type.GetMethod("Check").Invoke(extractor, null);
                result = (bool)type.GetMethod("Check").Invoke(extractor, null);
            }

            return false;
        }

        public static bool ExtractStream(Stream stream, string directory)
        {
            if (Check())
            {
                var type = assembly.GetType("SevenZip.SevenZipExtractor");
                var extractor = Activator.CreateInstance(type, new object[] { stream });
                type.GetMethod("ExtractArchive").Invoke(extractor, new object[] { directory });
                return true;
            }

            return false;
        }

        public static bool ExtractStream(Stream stream, string directory, string password)
        {
            if (Check())
            {
                var type = assembly.GetType("SevenZip.SevenZipExtractor");
                var extractor = Activator.CreateInstance(type, new object[] { stream, password });
                type.GetMethod("ExtractArchive").Invoke(extractor, new object[] { directory });
                return true;
            }

            return false;
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.Reflection.Assembly.LoadFrom")]
        public static bool Check()
        {
            if (assembly == null)
            {
                var localDirectory = Path.GetDirectoryName(new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath);
                if (localDirectory != null)
                {
                    var assemblyFilePath = Path.Combine(localDirectory, "SevenZipSharp.dll");
                    if (File.Exists(assemblyFilePath))
                    {
                        assembly = Assembly.LoadFrom(assemblyFilePath);
                    }
                    dllFound = File.Exists(Path.Combine(localDirectory, "7z.dll"));
                }
            }

            return assembly != null && dllFound;
        }
    }
}
